#include "demo.h"



int epd_epoll_noblock_set(int fd)
{
	int old_opt = fcntl(fd, F_GETFL);
	int new_opt = old_opt | O_NONBLOCK;
	
	if(old_opt < 0)
	{
		EPD_ERR("get old option failed, errno=%d.\n", errno);
		return old_opt;
	}
	
	new_opt = fcntl(fd, F_SETFL, new_opt);
	if(new_opt < 0)
	{
		EPD_ERR("set new option failed, errno=%d.\n", errno);
		return new_opt;
	}
	
	return old_opt;
}


int epd_epoll_fd_add(int epollfd, int fd, int oneshot)
{
	struct epoll_event event;
	event.data.fd = fd;
	event.events = EPOLLIN | EPOLLET;
	
	if(oneshot == EPD_TRUE)
	{
		event.events |= EPOLLONESHOT;
	}
	
	if(epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) != 0)
	{
		EPD_ERR("add fd failed, errno=%d.\n", errno);
		return EPD_FAILED;
	}
	
	if(epd_epoll_noblock_set(fd) < 0)
	{
		EPD_ERR("set noblock failed.\n");
		return EPD_FAILED;
	}
	
	return EPD_OK;
}


int epd_epoll_oneshot_reset(int epollfd, int fd)
{
	struct epoll_event event;
	event.data.fd = fd;
	event.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
	
	return epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
}


int epd_hostname_get(char* hostname, int len)
{
	if(EPD_UNLIKELY(hostname == NULL))
	{
		EPD_ERR("invalid parameters, hostname=%p.\n", hostname);
		return -EPD_INVALID_PARAM;
	}
	
	FILE* fp = popen("cat /proc/sys/kernel/hostname", "r");
	if(fp == NULL)
	{
		pclose(fp);
		return EPD_FAILED;
	}
	
	if(fgets(hostname, len, fp) != hostname)
	{
		pclose(fp);
		return EPD_FAILED;
	}
	
	if(strlen(hostname) > (len - 1))
	{
		hostname[len - 1] = 0;
	}
	else
	{
		hostname[strlen(hostname) - 1] = 0;
	}
	
	pclose(fp);
	return EPD_OK;
}


int epd_system(const char* cmd_str)
{
	if(EPD_UNLIKELY(cmd_str == NULL))
	{
		EPD_OUT("invalid parameters, cmd_str=%p.\n", cmd_str);
		return -EPD_INVALID_PARAM;
	}
	
	pid_t status = system(cmd_str);
	if(status == -1)
	{
		EPD_OUT("run \"%s\" failed, status [0x%08X].\n", cmd_str, status);
		return EPD_FAILED;
	}
	
	if(WIFEXITED(status) == 0)
	{
		EPD_OUT("run \"%s\" failed, status [0x%08X].\n", cmd_str, WEXITSTATUS(status));
		return EPD_FAILED;
	}
	
	if(WEXITSTATUS(status))
	{
		EPD_OUT("run \"%s\" failed, status [0x%08X].\n", cmd_str, WEXITSTATUS(status));
		return EPD_FAILED;
	}
	
	EPD_OUT("run \"%s\" ok, status [0x%08X].\n", cmd_str, status);
	return EPD_OK;
}


int epd_popen_cmd(const char* const cmd_str, char* const out_str, int len)
{
	char epd_error_tmp[256];
	char cmd_redirect_error[256];
	char errinfo_read[256];
	struct timespec tv;	
	int read_len;	
	int ret;

	EPD_OUT("cmd start: %s\n", cmd_str);

	if(EPD_UNLIKELY(cmd_str == NULL) || EPD_UNLIKELY(out_str == NULL))
	{
		EPD_OUT("invalid parameters, cmd_str=%p, out_str=%p.\n", cmd_str, out_str);
		return -EPD_INVALID_PARAM;
	}

	// redirect error to tmp file
	clock_gettime(CLOCK_REALTIME, &tv);
	snprintf(epd_error_tmp, sizeof(epd_error_tmp), "/tmp/dmd-%d-%lu", getpid(), tv.tv_sec );
	
	snprintf(cmd_redirect_error, sizeof(cmd_redirect_error), "%s 2>%s", cmd_str, epd_error_tmp);

	EPD_OUT("cmd with redirect error: %s\n", cmd_redirect_error);
	
	FILE* const fp = popen(cmd_redirect_error, "r");
	if(fp == NULL)
	{
		EPD_ERR("popen command \"%s\" open failed, errno=%d.\n", cmd_str, errno);
		return EPD_FAILED;
	}
	
	len = fread(out_str, 1, len-1, fp);
	if(ferror(fp) != 0)
	{
		EPD_ERR("popen command \"%s\" read failed, errno=%d, ferror=%d.\n", cmd_str, errno, ferror(fp));
	}

	out_str[len] = '\0';	

	EPD_OUT("cmd %s end, out : %s\n", cmd_str, out_str);
	ret = pclose(fp);

	FILE* fp_err = fopen(epd_error_tmp, "r");
	if ( fp_err == NULL )
	{
		EPD_ERR("fopen  %s  failed\n", epd_error_tmp);
	}
	else
	{
		read_len = fread(errinfo_read, 1, sizeof(errinfo_read)-1, fp_err);
		if(ferror(fp_err) != 0)
		{
			EPD_ERR("fread %s read failed, ferror=%d.\n", epd_error_tmp, ferror(fp_err));
		}
		else
		{
			if (read_len > 0)
			{
				EPD_OUT("cmd %s end, error : %s\n", cmd_redirect_error, errinfo_read);
			}
		}
		fclose(fp_err);

		// remove tmp file
		remove(epd_error_tmp);
	}	
	
	return ret;
}


int epd_popen_str(char* const out_str, int len, const char* format, ...)
{
	if(EPD_UNLIKELY(format == NULL) || EPD_UNLIKELY(out_str == NULL))
	{
		EPD_OUT("invalid parameters, format=%p, out_str=%p.\n", format, out_str);
		return -EPD_INVALID_PARAM;
	}
	
	char cmd_str[256];
	va_list args;
	va_start(args, format);
	vsprintf(cmd_str, format, args);
	va_end(args);
	
	return epd_popen_cmd(cmd_str, out_str, len);
}


int epd_popen_std(const char* format, ...)
{
	if(EPD_UNLIKELY(format == NULL))
	{
		EPD_OUT("invalid parameters, format=%p.\n", format);
		return -EPD_INVALID_PARAM;
	}
	
	char cmd_str[256];
	char out_str[256 << 4];
	
	va_list args;
	va_start(args, format);
	vsprintf(cmd_str, format, args);
	va_end(args);
	
	int ret = epd_popen_cmd(cmd_str, out_str, sizeof(out_str));
	EPD_OUT("%s", out_str);
	return ret;
}


